package com.ficus.road.maintain.authority.filter;

import com.alibaba.fastjson.JSON;
import com.ficus.road.maintain.authority.utils.JwtUtil;
import com.ficus.road.maintain.core.model.common.ErrorCodeDTO;
import com.ficus.road.maintain.core.model.common.ErrorDTO;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.AntPathMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * token的校验
 * 该类继承自BasicAuthenticationFilter，在doFilterInternal方法中，
 * 从http头的Authorization 项读取token数据，然后用Jwts包提供的方法校验token的合法性。
 * 如果校验通过，就认为这是一个取得授权的合法请求
 *
 * @author xxm
 */
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {
    public static final String[] AUTH_BLACKLIST = {
            "/ws/{carId}/{timestamp}",
            "/hits/sync",
            "/dianke/**"
    };
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String url = request.getRequestURI();
        String token = request.getHeader(JwtUtil.AUTHORIZATION);
        if (StringUtils.isBlank(token)) {
            token = request.getParameter("token");
        }
        //跳过不需要验证的路径
        if (!matchers(Arrays.asList(AUTH_BLACKLIST), url)) {
            chain.doFilter(request, response);
            return;
        }
        if (StringUtils.isBlank(token)) {
            response.setCharacterEncoding("UTF-8");
            ErrorDTO errorDTO = ErrorDTO.builder().message("Token为空!").retryable(false).code(ErrorCodeDTO.SERVER_BUSY).build();
            response.getWriter().write(JSON.toJSONString(errorDTO));
            return;
        }
        try {
            UsernamePasswordAuthenticationToken authentication = getAuthentication(token);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(request, response);
        } catch (Exception e) {
            response.setCharacterEncoding("UTF-8");
            ErrorDTO errorDTO = ErrorDTO.builder().message("Invalid Token!").retryable(false).code(ErrorCodeDTO.SERVER_BUSY).build();
            response.getWriter().write(JSON.toJSONString(errorDTO));
            logger.error("Invalid Token " + e.getMessage());
        }
    }

    boolean matchers(List<String> urls, String targetUrl) {
        AntPathMatcher matcher = new AntPathMatcher();
        for (String url : urls) {
            if (matcher.match(url, targetUrl)) {
                return true;
            }
        }
        return false;
    }

    private UsernamePasswordAuthenticationToken getAuthentication(String token) {
        if (token != null) {
            String userName = "";

            try {
                // 解密Token
                userName = JwtUtil.validateToken(token);
                if (StringUtils.isNotBlank(userName)) {
                    return new UsernamePasswordAuthenticationToken(userName, null, new ArrayList<>());
                }
            } catch (ExpiredJwtException e) {
                throw e;
                //throw new TokenException("Token已过期");
            } catch (UnsupportedJwtException e) {
                throw e;
                //throw new TokenException("Token格式错误");
            } catch (MalformedJwtException e) {
                throw e;
                //throw new TokenException("Token没有被正确构造");
            } catch (SignatureException e) {
                throw e;
                //throw new TokenException("签名失败");
            } catch (IllegalArgumentException e) {
                throw e;
                //throw new TokenException("非法参数异常");
            } catch (Exception e) {
                throw e;
                //throw new IllegalStateException("Invalid Token. "+e.getMessage());
            }
            return null;
        }
        return null;
    }

}
